#define LEV_BTN_UP    0    // level that button is released
#define LEV_BTN_DOWN  1    // level that button is pressed
#define DCLK_INTVAL 500   // ms, interval that two click within it is consider as double click
#define SHK_INTVAL 100    // ms, interval to reduce button shake


#define K_SPEED_UP   0
#define K_SPEED_DOWN 1


typedef struct {
  int pin;
  int level;
  bool is_pressed;
  bool is_click;
  bool is_dclick;

  unsigned long msec_level;    // milli second when read  
  unsigned long msec_pressed;  // milli second when pressed
  unsigned long msec_clicked;    // milli second when clicked
} BtnState_t;


enum EventType {BTN_UP, BTN_DOWN, CLICK, DCLICK};


typedef struct {
  EventType type;
  int key_code;
  unsigned long msec;  // milli second when the event happened
} Event_t;


/* @brief init the struct.
 * @param pin: the GPIO pin to read the signle
 */
void BtnInit(BtnState_t *btn, int pin) {
  btn->pin = pin;
  btn->level = BTN_UP;
  btn->is_pressed = false;
  btn->is_click = false;
  btn->is_dclick = false;

  btn->msec_level = 0;
  btn->msec_pressed = 0;
  btn->msec_clicked = 0;
}


void BtnUpdate(BtnState_t *btn) {
  int _level = digitalRead(btn->pin);
  BtnCkPress(btn, _level);
  
}


/* @brief Check if the key is pressed
 * @param
 *    btn: the struct carrys the information of key events.
 *    level: the level read from the IO port.
 *    msed: the milli second when the level is read.
 */
void BtnCkPress(BtnState_t *btn, int level, unsigned long msec) {
  if (BTN_UP == level) {
    btn->is_pressed = false;
  }
  else if (BTN_DOWN == level && BTN_UP == btn->level) {
    btn->msec_level = msec;
  }
  else if (BTN_DOWN == level && BTN_DOWN = btn->level
        && (msec - btn->mesc_level) > SHK_INTVAL) {
    btn->is_pressed = true;
    btn->msec_pressed = msec;
  }
  
  btn->level = level;
}


void BtnCkClick(BtnState_t *btn, int level, unsigned long msec) {
  if (btn->is_pressed) {
    btn->is_click = true;
    btn->msec_click = msec;
  }
  else if (BTN_DOWN = level) {
    btn->is_click = false;
  }     
}


void BtnCkDClick(BtnState_t *btn, int level, unsigned long msec) {
  if (btn->) {
    
  }
}


/* =========================================
 *  Main
 * ========================================= */
ButtonState_t kup, kdown;


void setup() {
  
}

void loop() {
  
}
